// ==UserScript==
// @name         追影
// @namespace    https://gitee.com/canqing86/tampermon
// @version      2025-10-22
// @description  来不及解释了，快上车！
// @author       vi

// @match       www.ecjson.com/*

// @match       x.video系列和欧
// @match        *.xvapp02.com/*
// @match        *.xvapp03.com/*
// @match        *.xnxxapp03.com/*
// @match        xhamster2.com/*
// @match        *.xhamster3.com/*
// @match        *.noodlemagazine.com/*


// @match       含羞.草
// @match        *://*/play/video/*
// @match        *://*/smallVideo/index/*

// @match       麻dou
// @match        *://madou.net/archives/*

// @match       高.清HD101
// @match        *://*/*watch?v=*

// @match       大哥系列
// @match        eeavx.com/*
// @match        javavx.com/*
// @match        missav.ai/*
// @match        7tv047.com/*
// @match        missav.ai/*
// @match        sezimu.com/*

// @match        其它：西兰、啪.哩啪.哩
// @match        *.onoaudio.com/*
// @match        web.jwybg.com/*

// @match        红.杏视频
// @include      /^https?:\/\/.*?\/html\/.*?\.html\?


// @run-at       document-end
// @grant        GM_log
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tom.com
// @license      MIT
// @require      https://gitee.com/canqing86/tampermon/raw/master/js/ajaxHooker.js
// @require      https://gitee.com/canqing86/tampermon/raw/master/js/crypto-js.js

// @downloadURL  https://gitee.com/canqing86/tampermon/raw/master/zhuiying.user.js
// @updateURL    https://gitee.com/canqing86/tampermon/raw/master/zhuiying.user.js
// ==/UserScript==

(function () {
    /*
    //临时存放数据
    // @require      https://scriptcat.org/lib/637/1.4.5/ajaxHooker.js#sha256=EGhGTDeet8zLCPnx8+72H15QYRfpTX4MbhyJ4lJZmyg=
    // @require      https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.js
    红杏匹配      *://*过滤/html/kkyd.html?m=*      *://*过滤/html/ar.html?v=*           *://*过滤/html/ar-kk.html?v=*
*/


    'use strict';
    //https://www.zhonghemuye.com/play/123-3-1.html

    let HanXiuCao_URL,obj,ads,show_videoUrl_bottom = 0,speedInterval
    let err_cnt = 0; //错误几次，多次就停止脚步
    const playerConfig = {
        playEl: null, // 播放器容器元素（选择器或DOM元素）
        episodeList: [], // 剧集列表（格式：[{name: "第1集", url: "..."}]
        SearchText: null,//搜索关键字
        Fanhao: null,//番号
        videoEl:null,//播放控制
    };


    console.log("【canqingav】脚本开始执行");

    // 动态加载外部JS   // @require
    function import_js(src) {
        let script = document.createElement('script'); // 创建 <script> 标签
        script.src = src; // 设置脚本的 src 属性
        document.head.appendChild(script); // 将脚本添加到 <head> 中
    }

    if (!location.href.match(/(\/watch\?v=|aacds)/)) {//排除不需要加载js，HD101不能注入
        import_js("https://cdnjs.cloudflare.com/ajax/libs/dplayer/1.26.0/DPlayer.min.js");
        import_js("https://libs.baidu.com/jquery/1.10.2/jquery.min.js");
        import_js("https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.1.5/hls.min.js");
    }



    // 启动拦截含羞草获取服务器地址
    /* global ajaxHooker */
    if (location.href.match("/play/video/") != null) {
        console.log("****对【含羞草】xhr/fetch进行了二次劫持，主要目的是获取服务器地址。");

        ajaxHooker.protect();
        ajaxHooker.filter([
            { type: 'xhr', url: '/videos/getInfo', method: 'POST', async: true },
        ]);

        ajaxHooker.hook(request => {
            HanXiuCao_URL = new URL(request.url);
            console.log("****拦截到的含羞草服务器地址：" + HanXiuCao_URL);
        });
    }

    //重置playerConfig的数据
    function resetPlayerConfig() {
        playerConfig.playEl = null;
        playerConfig.episodeList = [];
        playerConfig.SearchText = null;
        playerConfig.videoEl = null;
        playerConfig.Fanhao = null;
    }

    // 快进/快退
    function FaseForward(s) {
        let video = playerConfig.videoEl
        if(!video){video = document.querySelector(".dplayer-video")||playerConfig.playEl||document.querySelector("video");}
        //document.querySelector('video').currentTime = 10
        if (video) video.currentTime += s;
    }


    // 调整播放速度targetRate
    function PlaySpeed(targetRate) {

        let video = playerConfig.videoEl || document.querySelector(".dplayer-video") || playerConfig.playEl || document.querySelector("video");
        if (video) {
            video.playbackRate = targetRate;

            // 清除之前的定时器
            if (speedInterval) {
                clearInterval(speedInterval);
            }

            // 创建新的定时器来持续保持速度
            speedInterval = setInterval(() => {
                const currentVideo = playerConfig.videoEl || document.querySelector(".dplayer-video") || playerConfig.playEl || document.querySelector("video");
                if (currentVideo && currentVideo.playbackRate !== targetRate) {
                    currentVideo.playbackRate = targetRate;
                }
            }, 100);
        }
    }


    // 创建DPlayer播放器 同时也是 精简播放
    function createDPlayer(videoUrl, play_el) {
        if (typeof DPlayer === 'undefined') {alert("DPlayer 还没有加载完成！无法播放");return;}

        if (window.dp) {
            window.dp.pause()
            window.dp.destroy()
            window.dp = null;
        }

        /* 2. 新增播放器  在代码中添加注释，告诉它 DPlayer 是一个全局变量*/
        /* global DPlayer */
        window.dp = new DPlayer({
            element: play_el,
            autoplay: true, // 自动播放，默认为 false
            theme: '#FADFA3',
            loop: true, // 循环播放，默认为 false
            airplay: true, // 启用 AirPlay，仅在浏览器支持的情况下生效
            lang: 'zh',
            volume: 0.7, // 初始音量，范围是 0 到 1
            controls: true, // 显示控制条，默认为 true
            hotkeys: true, // 启用快捷键控制，默认为 true
            live: false, // 是否直播，默认为 false
            mutex: true, // 同一页面只能播放一个视频，默认为 true
            preload: 'auto', // 预加载策略，默认为 'auto'
            screenshot: true, // 截图功能，默认为 true
            poster: 'your_poster_url', // 如果不提供 video.pic，则此值作为封面
            video: {
                url: videoUrl,
                type: 'hls'
            }
        });

        /* 3. 设置播放器浮动显示,并添加一个具有上边距的兄弟div避免覆盖下面的内容 */
        //play_el.classList.add("my_add_header");
        play_el.style.position = 'sticky';
        play_el.style.zIndex = '999';
        play_el.style.top = '0';

        //play_el.style.height = '400px'; //指定高度
        //play_el.style.width = '100%';
        const maxHeight = window.innerHeight * 0.8; // 最大高度为窗口高度的80%
        const calculatedHeight = Math.min(play_el.offsetWidth * 9/16, maxHeight);
        play_el.style.height = `${calculatedHeight}px`;//计算窗口后设置高度

        var xxx = document.querySelector("#my_add_sibling");
        if(!xxx){
            var sibling = document.createElement('div');
            sibling.id = "my_add_sibling";
            //sibling.style.marginTop = play_el.offsetHeight + 'px'; // 设置兄弟元素的顶部边距
            play_el.after(sibling);
        }



    }

    // 播放视频字典数组
    function play_EpisodeList() {
        // 检查参数是否有效
        if (!playerConfig.episodeList || !playerConfig.playEl) {
            console.error(`部分参数无效，剧集列表：${playerConfig.episodeList}、播放器位置：${playerConfig.playEl}`);
            return;
        }

        // 检查剧集列表是否为空
        if (playerConfig.episodeList.length === 0) {
            console.error("剧集列表为空，无法播放");
            return;
        }

        // 显示视频链接信息
        show_videoUrl();

        // 创建播放器，默认播放第一个剧集
        createDPlayer(playerConfig.episodeList[0].url, playerConfig.playEl); // 使用全局配置创建播放器
    }

    // 隐藏工具栏菜单
    function handleSecretMenu() {
        // 获取工具栏和切换按钮元素
        const container = document.getElementById("video-controls-container");
        const toggleBtn = document.getElementById("video-controls-toggle");

        // 如果工具栏存在，则隐藏它
        if (container) {
            container.style.display = "none";
        }

        // 如果切换按钮不存在，则重新创建它
        if (!toggleBtn) {
            const newToggleBtn = document.createElement("button");
            newToggleBtn.id = "video-controls-toggle";
            newToggleBtn.textContent = "⚙️";
            newToggleBtn.style.cssText = `
				position: fixed;        /* 固定定位（相对于浏览器视口定位） */
				bottom: 20px;          /* 距离视口底部20像素 */
				left: 20px;            /* 距离视口左侧20像素（定位在左下角） */
				z-index: 9999;         /* 设置极高堆叠顺序（确保显示在最顶层） */
				padding: 8px 16px;     /* 内边距：上下8像素/左右16像素 */
				background: rgba(194,30,86,0.5); /* 半透明玫红色背景（RGB值194,30,86，透明度50%） */
				color: white;          /* 文字颜色为白色 */
				border: none;          /* 无边框样式 */
				border-radius: 20px;   /* 20像素圆角半径（形成胶囊按钮效果） */
				font-size: 14px;       /* 字体大小14像素 */
				cursor: pointer;       /* 鼠标悬停时显示手指指针（表示可点击） */
				transition: opacity 0.3s; /* 透明度变化时添加0.3秒平滑过渡效果 */
        `;
            newToggleBtn.addEventListener("click", function() {
                if (container) container.style.display = "flex";
                this.style.display = "none";
            });
            document.body.appendChild(newToggleBtn);
        } else {
            // 如果切换按钮已存在，则显示它
            toggleBtn.style.display = "block";
        }
    }




    // 创建工具栏菜单 show_videoUrl_bottom
    function show_videoUrl() {
        // 清理旧元素
        const oldContainer = document.getElementById("video-controls-container");
        if (oldContainer) oldContainer.remove();
        const oldToggleBtn = document.getElementById("video-controls-toggle");
        if (oldToggleBtn) oldToggleBtn.remove();

        // 设置默认底部距离
        if (typeof show_videoUrl_bottom === 'undefined' || show_videoUrl_bottom === null) {
            show_videoUrl_bottom = 0;
        }

        // 创建主容器
        const container = document.createElement("div");
        container.id = "video-controls-container";
        container.style.cssText = `
			position: fixed;        /* 固定定位（相对于浏览器窗口） */
			bottom: ${show_videoUrl_bottom}px;             /* 贴紧窗口底部边缘 */
			left: 0px;              /* 贴紧窗口左侧边缘 */
			right: 0px;             /* 贴紧窗口右侧边缘（与left:0组合实现全宽度） */
			z-index: 9999;        /* 最高层级（确保覆盖其他元素） */
			display: flex;       /* 初始显示flex,初始隐藏none（需通过JS控制显示） */
			flex-direction: column-reverse;  /* 弹性容器反向纵向排列（最后元素显示在最前） */
    `;

        // 创建切换按钮（初始显示）
        const toggleBtn = document.createElement("button");
        toggleBtn.id = "video-controls-toggle";
        toggleBtn.textContent = "⚙️";
        toggleBtn.style.cssText = `
			position: fixed;        /* 固定定位（脱离文档流） */
			bottom: ${show_videoUrl_bottom}px;          /* 距离视口底部20px */
			left: 20px;            /* 距离视口左侧20px（左下角定位） */
			z-index: 9999;         /* 堆叠层级（确保在最顶层显示） */
			padding: 8px 16px;     /* 内边距：垂直8px/水平16px */
			background: rgba(194,30,86,0.5); /* 半透明玫红背景（RGB194,30,86 透明度50%） */
			color: white;          /* 文字颜色为纯白 */
			border: none;          /* 完全移除边框 */
			border-radius: 20px;   /* 20px圆角（胶囊按钮效果） */
			font-size: 14px;       /* 标准字号14像素 */
			cursor: pointer;       /* 鼠标悬停时变为手型指针 */
			transition: opacity 0.3s; /* 透明度变化添加0.3秒平滑过渡 */
    `;
        toggleBtn.addEventListener("click", function() {
            container.style.display = "flex";
            this.style.display = "none";
        });
        document.body.appendChild(toggleBtn);

        // 基础控制栏（始终置底）
        const baseBar = document.createElement("div");
        baseBar.id = "video-controls-baseBar";
        baseBar.style.cssText = `
			background: rgba(0,0,0,0.5);  /* 半透明黑色背景（透明度50%） */
			padding: 6px 8px;             /* 内边距：上下6px，左右8px */
			display: flex;                /* 启用Flex布局 */
			gap: 4px;                     /* 子元素间距4px */
			flex-wrap: nowrap;            /* 禁止子元素换行 */
			overflow-x: auto;             /* 水平方向溢出时显示滚动条 */
			align-items: center;          /* 垂直居中对齐子元素 */
		`;

        // 基础控制按钮
        const baseControls = createToolbar([
            {text: '30秒', onClick: () => FaseForward(30)},
            {text: '2分', onClick: () => FaseForward(120)},
            {text: '5分', onClick: () => FaseForward(300)},
            {text: '10分', onClick: () => FaseForward(600)},
            {text: '退1分', onClick: () => FaseForward(-60)},
        ]);
        baseBar.appendChild(baseControls);

        // 更多按钮
        const expandBtn = createButton('⋮', toggleExpand);
        expandBtn.style.cssText = `
			padding: 6px 8px;   /* 内边距：上下6px，左右8px */
			border: none;       /* 移除所有边框 */
			border-radius: 4px; /* 4像素圆角 */
			background: #C21E56;/* 玫红色背景 */
			color: white;       /* 白色文字 */
			font-size: 14px;    /* 14像素字号 */
			cursor: pointer;    /* 手型鼠标指针 */
			min-width: 50px;    /* 最小宽度30像素 */
			flex-shrink: 0;     /* 禁止flex元素收缩 */
		`;
        baseBar.appendChild(expandBtn);

        // 切换展开状态
        let isExpanded = false;
        function toggleExpand() {
            isExpanded = !isExpanded;
            expandArea.style.display = isExpanded ? 'flex' : 'none';
            expandBtn.textContent = isExpanded ? '×' : '⋮';
        }

        // 扩展区域容器
        const expandArea = document.createElement("div");
        expandArea.style.cssText = `
			background: rgba(0,0,0,0.8);  /* 黑色半透明背景（透明度80%） */
			padding: 8px;                /* 内边距8像素（四周等距） */
			display: none;               /* 初始隐藏状态（需通过JS控制显示） */
			flex-direction: column;      /* 弹性布局：垂直排列子元素 */
			gap: 8px;                    /* 子元素间距8像素 */
			border-bottom: 1px solid #555; /* 底部边框：1像素实线（深灰色#555） */
    `;

        // 剧集列表（按钮+链接）
        if (playerConfig.episodeList?.length) {
            const episodeWrapper = document.createElement("div");
            episodeWrapper.style.display = "flex";
            episodeWrapper.style.flexDirection = "column";
            episodeWrapper.style.gap = "4px";

            playerConfig.episodeList.forEach(ep => {
                const itemContainer = document.createElement("div");
                itemContainer.style.display = "flex";
                itemContainer.style.gap = "4px";
                itemContainer.style.alignItems = "center";

                // 播放按钮
                const btn = createButton(ep.name, () => createDPlayer(ep.url, playerConfig.playEl));
                btn.style.flex = "0 1 80px";

                // 链接元素
                const link = document.createElement("a");
                link.href = ep.url;
                link.textContent = ep.url;
                link.target = "_blank";
                link.style.cssText = `
                flex: 1;
                color: #FF637E;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                font-size: 14px;
                padding: 6px;
                background: rgba(255,255,255,0.1);
                border-radius: 4px;
            `;

                itemContainer.appendChild(btn);
                itemContainer.appendChild(link);
                episodeWrapper.appendChild(itemContainer);
            });
            expandArea.appendChild(episodeWrapper);
        }

        // 扩展区域3：搜索相关
        if (playerConfig.SearchText) {
            expandArea.appendChild(createToolbar([
                {text: '主页', onClick: () => window.location.href = location.origin},
                {text: '百度', onClick: () => window.open(`https://www.baidu.com/s?wd=${playerConfig.SearchText}`)},
                {text: 'Bing', onClick: () => window.open(`https://bing.com/search?q=${playerConfig.SearchText}`)},
                {text: 'Yandex', onClick: () => window.open(`https://ya.ru/search/?text=${playerConfig.SearchText}`)},
            ]));
        }

        // 扩展区域2：番号相关
        if (playerConfig.FanHao) {
            expandArea.appendChild(createToolbar([
                {text: 'MissAv', onClick: () => window.open(`https://missav.ai/cn/search/${playerConfig.FanHao}`)},
                {text: 'Su606', onClick: () => window.open(`https://eeavx.com/zh/maker/?key=${playerConfig.FanHao}`)},
                {text: 'JavAvx', onClick: () => window.open(`https://javavx.com/zh/v/${playerConfig.FanHao}`)},
                {text: '7MM', onClick: () => window.open(`https://7tv047.com/zh/search/${playerConfig.FanHao}`)},
            ]));
        }

        // 扩展区域1：速度控制
        const speedBar = createToolbar([
            {text: '1.0x', onClick: () => PlaySpeed(1)},
            {text: '1.8x', onClick: () => PlaySpeed(1.8)},
            {text: '3.0x', onClick: () => PlaySpeed(3)},
            {text: '5.0x', onClick: () => PlaySpeed(5)},
            {text: '隐藏', onClick: () => handleSecretMenu()},
        ]);
        expandArea.appendChild(speedBar);

        // 组装结构
        container.appendChild(baseBar);
        container.appendChild(expandArea);
        document.body.appendChild(container);

        // 工具函数：创建按钮，控制栏按钮都是调用此函数
        function createButton(text, onClick) {
            const btn = document.createElement("button");
            btn.textContent = text;
            btn.style.cssText = `
				padding: 6px 8px;        /* 内边距：垂直6px/水平8px */
				border: none;           /* 完全移除边框线 */
				border-radius: 2px;     /* 2px圆角（注意修正原代码中的空格错误） */
				background: #C21E56;    /* 品牌玫红色背景（HEX色值） */
				color: white;           /* 纯白文字颜色 */
				font-size: 14px;        /* 标准正文字号（原注释建议可移除） */
				cursor: pointer;        /* 交互指针（手型图标） */
				min-width: 60px;        /* 最小宽度约束（避免内容挤压） */
				flex-shrink: 0;         /* 弹性项抗收缩属性（保持固定尺寸） */
        `;
            btn.addEventListener('click', onClick);
            return btn;
        }

        // 工具函数：创建工具栏中间的按钮函数
        function createToolbar(buttons) {
            const bar = document.createElement("div");
            bar.style.cssText = `
                display: flex;
                gap: 4px;
                flex-wrap: nowrap;      /* 改为 nowrap 确保不换行 */
                `;
            buttons.forEach(config => {
                bar.appendChild(createButton(config.text, config.onClick));
            });
            return bar;
        }


    }




    // 错误处理
    function show_err_log(err) {
        err && console.log(err);
        err_cnt++;
        if (err_cnt >= 10) {
            const errDiv = document.createElement('div');
            errDiv.innerHTML = `
                <div id="my_add_err_log" style="color:red;font-size:14px">
                    解析出错，1.检查是否登录！2.请仔细阅读<a href="https://sleazyfork.org/zh-CN/scripts/456496" target="_blank">【脚本说明】</a>查看是否支持你的平台组合，
                    如需帮助请复制以下内容到脚本评论区，等候作者处理! 请加上使用的平台组合，如：chrome + tampermonkey 。
                    <p style="color:red;font-size:14px">错误信息：${err || "尝试多次仍然未获取到地址,可能是网站已更新..."}</p>
                    <p style="color:red;font-size:14px">操作系统：${navigator.platform}</p>
                    <p style="color:red;font-size:14px">浏览器：${navigator.userAgent}</p>
                    <p style="color:red;font-size:14px">当前地址：${location.href}</p>
                </div>`;
            document.querySelector("head").after(errDiv);
            clearInterval(my_timer);
        }
    }

    /*
    const episodeList = [
    { name: "第1集", url: "https://example.com/video1.mp4" },
    { name: "第2集", url: "https://example.com/video2.mp4" },
    { name: "第3集", url: "https://example.com/video3.mp4" }
    ];
    play_EpisodeList(episodeList, "player-container", "info-container", "搜索文本");
    show_videoUrl(episodeList, "show-container", "搜索关键字", "player-container");
*/



    /*============================================================================================*/
    // 主程序
    function get_videourl() {
        try {
            console.log("【v】进入追影主程序...");
            resetPlayerConfig() //重置playerConfig

            if (location.href.match(".*xvapp.*.com/video|xnxxapp.*.com/video")) {
                console.log("【v】[xvi_deo][xx_nn]...");
                playerConfig.playEl = document.querySelector("#video-tabs")||document.querySelector(".video-title-container")
                playerConfig.SearchText = (document.querySelector("#main > h2")||document.querySelector("#video-content-metadata > div.clear-infobar > div.video-title-container > div > strong")).innerText
                playerConfig.episodeList = [{ name: "播放", url: document.querySelector("#hlsplayer > div.video-bg-pic > video").src },];
                playerConfig.videoEl = document.querySelector("video")
                show_videoUrl();
                clearInterval(my_timer);

            } else if (location.href.match("/smallVideo/index")) {
                console.log("【v】含羞草短视频...");

                const Short_count = JSON.parse(localStorage.getItem('visitorShortLimit'));
                if (Short_count) {
                    localStorage.setItem("visitorShortLimit", JSON.stringify({ ...Short_count, count: -999 }));
                    clearInterval(my_timer);

                }
            } else if (location.href.match("/play/video/")) {//canqing86@outlook.com @Wf123123
                console.log("【v】含羞草破解...");
                HanXiuCaoVip();

            } else if (location.href.match("madou.*?/archives")) {
                console.log("【v】[麻豆]视频页面...");
                ads=document.querySelector("body > main > article > div.domainBox");if (ads != null) ads.remove();
                playerConfig.playEl = document.querySelector("video")
                playerConfig.SearchText = document.querySelector("body > header > h1").outerText
                show_videoUrl()
                clearInterval(my_timer);

            }else if (location.href.match("noodlemagazine.com")) {
                console.log("【v】[noodlemagazine.com]视频页面...");
                playerConfig.playEl = document.querySelector("video")
                playerConfig.SearchText = document.querySelector("head > title").outerText
                show_videoUrl()
                clearInterval(my_timer);

            } else if (location.href.match("/#/long/play/")) {
                console.log("【v】[啪哩啪哩]视频页面...");
                PiLioVip();

            } else if (location.href.match(/618281.xyz/)) {
                clearInterval(my_timer);
                console.log("[红杏]视频页面...");
                playerConfig.playEl = document.querySelector("div.myplayer")
                playerConfig.SearchText = document.querySelector("#hekund")

                show_videoUrl_bottom = 150 //控制栏距离底边
                const maxHeight = window.innerHeight * 0.2;
                createSniffButton(maxHeight,"div.myplayer");//"div.myplayer"元素保留，其余全部删除。


            } else if (location.href.match(/\?v=/)) {
                clearInterval(my_timer);
                console.log("[avhd101]视频页面...");
                avhd101();
                //createSniffButton(); // 获取所有网络请求查找播放地址

            }

            else {
                console.log("【v】其他视频.show_videoUrl..");
                //playerConfig.episodeList = [{ name: "第1集", url: "https://example.com/video1.mp4" },{ name: "第2集", url: "https://example.com/video2.mp4" },];
                //playerConfig.SearchText = "关键字";
                //playerConfig.FanHao = "追";
                show_videoUrl()
                clearInterval(my_timer);
            }
        } catch (err) {
            console.log(`${err}`);
            show_err_log(err);
        }
    }


    let my_timer = setInterval(get_videourl, 2000);

    // 监听URL变化
    let oldhref = location.href;
    setInterval(function () {
        if (location.href != oldhref) {
            clearInterval(my_timer);
            console.log("监听到地址变化,先停止my_timer，再次启动【获取视频定时器】!");
            if (speedInterval) {clearInterval(speedInterval);}//清除播放速率的定时器
            oldhref = location.href;
            err_cnt = 0;
            my_timer = setInterval(get_videourl, 2000);
            console.log("【v】监听到地址变化,my_timer：" + my_timer);
        }
    }, 1000);


    /*===============================================================================================*/



    // 获取所有网络请求查找播放地址 bottom_a：距离底部距离,onlyEl:该页面只保留一个EL（元素名），其余BOBY.html全部清空
    function createSniffButton(bottom_a,onlyEl) {
        console.log("【v】****fetchUrl/createSniffButton获取所有网络请求****");

        // 检查是否已存在按钮
        if (document.getElementById("open-media-links-button")) {
            console.log("按钮已存在，无需重复创建");
            return;
        }

        // 设置默认底部距离
        if (typeof bottom_a === 'undefined' || bottom_a === null) {
            bottom_a = 100;
        }

        // 创建嗅探视频按钮
        const button = document.createElement("button");
        button.id = "open-media-links-button"; // 设置唯一标记
        button.textContent = "【嗅探视频】";
        button.style.position = "fixed";
        button.style.bottom = bottom_a + "px"; // 使用参数设置底部距离
        button.style.right = "20px";
        button.style.zIndex = 10000;
        button.style.padding = "10px 20px";
        button.style.backgroundColor = "#007bff";
        button.style.color = "#fff";
        button.style.border = "none";
        button.style.borderRadius = "5px";
        button.style.cursor = "pointer";

        // 添加按钮到页面
        document.body.appendChild(button);

        // 按钮点击事件
        button.addEventListener("click", () => {
            //按钮被点击
            // 获取所有网络请求
            const resources = performance.getEntriesByType("resource");

            // 过滤出媒体资源（如视频、音频），并排除包含 check=true& 的URL
            let mediaUrls = resources.filter((resource) => {
                return (resource.name.includes(".mp") || resource.name.includes(".m3u8")) &&
                    !resource.name.includes("check=true&");
            }).map((resource) => resource.name);

            // 输出抓取的媒体链接
            console.log("****抓取的媒体链接:", mediaUrls);

            // 如果没有抓取到有效链接，提示用户
            if (mediaUrls.length === 0) {
                alert("未找到有效的媒体链接");
                return;
            }


            //页面中只保留一个元素，目的是去除广告等代码
            if (typeof onlyEl != 'undefined' || onlyEl != null) {
                console.log("****页面中只保留一个元素，目的是去除广告等代码", );
                // 1. 获取目标元素
                const playerEl = document.querySelector(onlyEl);

                // 2. 清空整个 body
                document.body.innerHTML = '';

                // 3. 把播放器元素重新加回去
                if (playerEl) {
                    document.body.appendChild(playerEl);
                } else {
                    console.warn("未找到元素！"+onlyEl);
                }
            }



            // 创建一个字典数组，存储剧集名称和播放地址，用于传递播放。
            const episodeList = mediaUrls.map((url, index) => {
                return {
                    name: `播放 ${index + 1}`, // 剧集名称，如 "第1集"
                    url: url // 播放地址
                };
            });
            // 输出字典数组
            console.log("****剧集列表:", episodeList);
            // 更新 playerConfig 中的剧集列表
            playerConfig.episodeList = episodeList;

            // 调用播放函数，使用 playerConfig 中的配置
            play_EpisodeList();
            if (document.getElementById("open-media-links-button")) {
                document.getElementById("open-media-links-button").remove()
            } //删除嗅探
        });
    }





    // 啪哩啪哩
    function PiLioVip() {

        let vuex = JSON.parse(localStorage.getItem('vuex'))
        vuex.userInfo.level = 99
        vuex.userInfo.vip_trial = true
        vuex.newPromotion.view_amount = 15
        vuex.newPromotion.view_limit = 80
        vuex.newPromotion.vip_ticket_amount = 92
        localStorage.setItem("vuex",JSON.stringify(vuex))

        playerConfig.playEl = document.querySelector(".player-banner")
        playerConfig.SearchText = document.querySelector("div.title-content").innerText

        createSniffButton();
        clearInterval(my_timer);


    }


    // 含羞草破解
    function HanXiuCaoVip(){//含羞草破解 https://www.dapa6.com/play/video/43718/0
        clearInterval(my_timer);
        let PRE_URL
        let date_day = Math.floor(Date.parse(new Date) / 86400000)//6.29是19903
        let localStorage_VITE_APP_SERVER_ADDRESS = JSON.parse(localStorage.getItem('VITE_APP_SERVER_ADDRESS'))

        if (!localStorage_VITE_APP_SERVER_ADDRESS || date_day != localStorage_VITE_APP_SERVER_ADDRESS.date_day){
            //PRE_URL = "https://ap988.hydzswyxgs.com/videos/getPreUrl"
            if (!HanXiuCao_URL.host){HanXiuCao_URL.host="https://ap988.hydzswyxgs.com/videos/getPreUrl"}

            PRE_URL = "https://" + HanXiuCao_URL.host + "/videos/getPreUrl"
            var SERVER_ADDRESS = {
                date_day: date_day,
                ADDRESS: PRE_URL,
            };
            var json_SERVER_ADDRESS = JSON.stringify(SERVER_ADDRESS);
            console.log("****将获取到含羞草新的服务器地址存到localStorage："+json_SERVER_ADDRESS)
            localStorage.setItem("VITE_APP_SERVER_ADDRESS",json_SERVER_ADDRESS)

        }else{
            PRE_URL = JSON.parse(localStorage.getItem('VITE_APP_SERVER_ADDRESS')).ADDRESS
        }


        //==================开始获取试看地址，然后修改成真实播放地址。

        // 权限认证标识
        const TOKEN = 'hxc_1.0.0_token';
        // 服务地址
        let baseUrl = location.origin;
        // 视频试看地址
        //const PRE_URL = baseUrl + '/api/videos/getPreUrl';
        //const PRE_URL = 'https://ap988.hydzswyxgs.com/videos/getPreUrl'
        //PRE_URL改为动态获取

        // 用户注册地址
        const REG_URL = baseUrl + '/api/login/userReg';
        var videoUrl = "";

        // 参数加密
        // 定义一个名为Encrypt的函数，接收一个名为word的参数，这个参数是需要被加密的字符串
        function Encrypt(word) {

            let keyStr = 'B77A9FF7F323B5404902102257503C2F';// 定义一个字符串keyStr，这个字符串用作AES加密的密钥和初始化向量（IV）
            const key = CryptoJS.enc.Utf8.parse(keyStr);// 使用CryptoJS库的Utf8.parse方法将keyStr字符串转换为WordArray格式，用作AES加密的密钥
            const iv = CryptoJS.enc.Utf8.parse(keyStr);// 同样地，使用CryptoJS库的Utf8.parse方法将keyStr字符串转换为WordArray格式，用作AES加密的初始化向量（IV）
            const srcs = CryptoJS.enc.Utf8.parse(word);// 使用CryptoJS库的Utf8.parse方法将需要加密的word字符串转换为WordArray格式
            const encrypted = CryptoJS.AES.encrypt(srcs, key, {// 使用CryptoJS库的AES.encrypt方法执行AES加密操作 // 参数srcs是要加密的明文 // 参数key是加密密钥 // 第三个参数是一个配置对象，其中：
                iv: iv, // iv: 定义了初始化向量（IV）
                mode: CryptoJS.mode.CBC,// mode: 定义了加密模式为CBC
                padding: CryptoJS.pad.Pkcs7 // padding: 定义了填充方式为PKCS7
            });
            let bb = CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
            return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);// 使用CryptoJS库的Base64.stringify方法将加密后的密文转换为Base64字符串格式，便于存储和传输
        }

        const Z = new Date;
        console.log("****服务器系统时间戳",parseInt(Z.getTime() / 1e3) + Z.getTimezoneOffset() * 60,"加密后得到：",Encrypt(parseInt(Z.getTime() / 1e3) + Z.getTimezoneOffset() * 60))
        console.log("****准备执行 fetch请求：")

        // 请求封装
        const fetchData = async (url, body) => {
            const Z = new Date;

            return fetch(url, {
                method: 'post',
                body: JSON.stringify({
                    endata: Encrypt(JSON.stringify(body)),
                    ents:Encrypt(parseInt(Z.getTime() / 1e3) + Z.getTimezoneOffset() * 60),
                }),
                headers: {
                    // 携带认证头
                    auth: localStorage.getItem(TOKEN)?.replace(/"/g, ''),
                    'Content-Type': 'application/json'
                }
            });
        };

        if (document.querySelector("#failurl")){document.querySelector("#failurl").remove()}

        getHanxiucaoVideoUrl()

        //获取视频链接
        async function getHanxiucaoVideoUrl(){

            let videoId = location.href.match(/.+\/www\..+\/play\/video\/(\d+)\/.+/)||location.href.match(/.+\/play\/video\/(\d+)/);
            console.log("****获取到videoId，并等待fetchData结果！！！")
            let json =await fetchData(PRE_URL, {
                videoId: Number(videoId[1])
            }).then(response => {
                return response.json();
            });

            const isSuccess = !!json.data.url;
            if (isSuccess) {
                clearInterval(my_timer);
                let preUrl = json.data.url;
                playerConfig.episodeList.push({name: "【试看】", url: preUrl});
                let parseUrl = json.data.url.replace(/start=\d+&end=\d+/, '');
                playerConfig.episodeList.push({name: "【破解】", url: parseUrl});
                console.log("获取到播放地址并替换掉试看限制去掉start和end：",parseUrl)
                let ads = document.querySelector("div.try-detail-video.try-before.g-absolute.g-w.g-flex.g-flex-fdc.g-flex-aic.boxBackground.textcss");if (ads != null) ads.remove();
                ads = document.querySelector("div.g-m-r-10.g-flex.g-flex-jcc.g-flex-aic");if (ads != null) ads.remove();
                ads = document.querySelector("div.g-m-t-3.box.g-p-l-16.g-p-r-16");if (ads != null) ads.style.display = "none";

                playerConfig.playEl = document.querySelector("#xgPlayer")||document.querySelector("div.relative.bg-overlay")
                playerConfig.SearchText = (document.querySelector("div.w-300.hide")||document.querySelector(".article-title")).innerText
                play_EpisodeList()
            }else{
                //没有的到有效数据，提示。
                const jsonText = JSON.stringify(json);

                const targetElement = document.querySelector("div.g-p-l-16.g-p-r-16.user > div.g-m-t-8") || document.querySelector("div.relative.bg-overlay");
                if (targetElement) {targetElement.insertAdjacentHTML('afterend', `<pre id="failurl" style="white-space: pre-wrap;color: red;">${jsonText}</pre>`);}
            }

        }
    } //含.羞.草.函数结束


    //AVHD101
    function avhd101(){
        ads = document.querySelector("div.video-plan");if(ads){ads.remove()}
        ads = document.querySelector("div.adblock");if(ads){ads.remove()}

        playerConfig.playEl = document.querySelector("#player")
        playerConfig.videoEl = document.querySelector('video')


        const listItems = document.querySelectorAll('.video-info li');
        for (const li of listItems) {
            const span = li.querySelector('span');
            if (!span) continue;

            const textN = span.textContent.trim();
            // 提取片名（注意：片名在 <p> 中，不在 <a>）
            if (textN === '片名') {
                const p = li.querySelector('p'); // 获取第一个 <p> 标签
                if (p) {
                    playerConfig.SearchText = p.textContent.trim()
                        .replace(/\s+/g, ' '); // 清理多余空格
                }
            }

            // 提取番号（番号在 <a> 中）
            if (textN === '番号') {
                const link = li.querySelector('a');
                if (link) {
                    playerConfig.FanHao = link.textContent.trim();
                }
            }
        }

        let tryurl = document.querySelector("#my-player_html5_api > source")
        if(tryurl){playerConfig.episodeList = [{name: "试看", url: tryurl.src}]; }
        //play_EpisodeList()
        show_videoUrl();
    }



    // 页面卸载时清理
    window.addEventListener('beforeunload', () => {
        if (speedInterval) {
            clearInterval(speedInterval);
            speedInterval = null;
        }
    });

})();